﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Deferred.Library.Configuration
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="newLine"></param>
    public delegate void OutputUpdateEvent(string newLine);

    /// <summary>
    /// 
    /// </summary>
    public interface ICommandLineEngine
    {
        /// <summary>
        /// 
        /// </summary>
        List<string> Output { get; }
        /// <summary>
        /// 
        /// </summary>
        List<string> CommandHistory { get; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        void ProcessInput(string input);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Help"></param>
        /// <param name="Callback"></param>
        void AddCommand(string Name, string Help, CommandCallback Callback);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        void AddCommand(Command command);
        /// <summary>
        /// 
        /// </summary>
        event OutputUpdateEvent OutputChanged;
    }

    /// <summary>
    /// 
    /// </summary>
    public class CommandLineEngine : ICommandLineEngine
    {
        private Dictionary<string, Command> commands = new Dictionary<string, Command>();

        /// <summary>
        /// 
        /// </summary>
        public event OutputUpdateEvent OutputChanged = delegate { };

        /// <summary>
        /// 
        /// </summary>
        public List<string> Output { get; private set; }
        /// <summary>
        /// 
        /// </summary>
        public List<string> CommandHistory { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        public CommandLineEngine()
        {
            Output = new List<string>();
            CommandHistory = new List<string>();
            AddCommand("help", "Shows all the commands",
                delegate(string[] arguements) {
                    if (1 == arguements.Length)
                    {
                        StringBuilder builder = new StringBuilder();
                        foreach (Command command in commands.Values)
                        {
                            builder.Append("\r\n");
                            builder.Append(command.Name + "\t" + command.Help);
                        }
                        builder.Remove(0, 2);
                        return builder.ToString();
                    }
                    else if (2 == arguements.Length)
                    {
                        if (!commands.ContainsKey(arguements[1])) return "No command '" + arguements[1] + "'";
                        return commands[arguements[1]].Help;
                    }
                    return "Invalid number of arguements";
                }
            );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Help"></param>
        /// <param name="Callback"></param>
        public void AddCommand(string Name, string Help, CommandCallback Callback)
        {
            AddCommand(new Command(Name, Help, Callback));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public void AddCommand(Command command)
        {
            if (!commands.ContainsKey(command.Name)) commands.Add(command.Name, command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        public void ProcessInput(string input)
        {
            string[] arguements = input.Split(' ');
            String newLine = null;

            if (commands.ContainsKey(arguements[0]))
            {
                CommandHistory.Insert(0, input);
                newLine = commands[arguements[0]].Callback(arguements);
            }
            else
            {
                newLine = "No command '" + arguements[0] + "'";
            }
            if (!String.IsNullOrEmpty(newLine)) Print(newLine);
            
        }

        private void Print(string newLine)
        {
            Output.Add(newLine);
            if (OutputChanged != null)
            {
                OutputChanged(newLine);
            }
        }
    }
}
